package com.wss.lsl.test.driven.concurrent;

import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

public class FutureTaskDemo {

	public static void main(String[] args) throws InterruptedException,
			BrokenBarrierException {
		int numberOfThreads = 100;

		long timer = System.currentTimeMillis();
		Computable<String, Integer> computable = new CompltableImpl();
		Memoizer3<String, Integer> memoizer3 = new Memoizer3<String, Integer>(
				computable);
		CyclicBarrier entryBarrier = new CyclicBarrier(numberOfThreads + 1);
		CyclicBarrier exitBarrier = new CyclicBarrier(numberOfThreads + 1);

		for (int i = 0; i < numberOfThreads; i++) {
			new Thread(new RunnableImpl(entryBarrier, memoizer3, exitBarrier))
					.start();
		}

		entryBarrier.await();
		exitBarrier.await();
		System.out.println("time: " + (System.currentTimeMillis() - timer));

		System.out.println(memoizer3.compute("3"));
		System.out.println(memoizer3.compute("3"));
	}
}

class RunnableImpl implements Runnable {

	private CyclicBarrier entryBarrier;
	private Memoizer3<String, Integer> memoizer3;
	private CyclicBarrier exitBarrier;

	private static Random random = new Random();

	public RunnableImpl(CyclicBarrier entryBarrier,
			Memoizer3<String, Integer> memoizer3, CyclicBarrier exitBarrier) {
		super();
		this.entryBarrier = entryBarrier;
		this.memoizer3 = memoizer3;
		this.exitBarrier = exitBarrier;
	}

	@Override
	public void run() {
		try {
			entryBarrier.await();
			memoizer3.compute("" + random.nextInt(100000));
			exitBarrier.await();
		} catch (InterruptedException e) {
			Thread.currentThread().interrupt();
		} catch (BrokenBarrierException e) {
			e.printStackTrace();
		}
	}

}

interface Computable<A, V> {

	V compute(A v) throws InterruptedException;
}

class CompltableImpl implements Computable<String, Integer> {

	@Override
	public Integer compute(String v) throws InterruptedException {
		return Integer.valueOf(v);
	}

}

class Memoizer3<A, V> implements Computable<A, V> {

	private ConcurrentHashMap<A, Future<V>> cached = new ConcurrentHashMap<A, Future<V>>();
	private Computable<A, V> computable;

	public Memoizer3(Computable<A, V> computable) {
		super();
		this.computable = computable;
	}

	@Override
	public V compute(final A arg) throws InterruptedException {
		while (true) {
			Future<V> f = cached.get(arg);
			if (f == null) {
				Callable<V> eval = new Callable<V>() {

					@Override
					public V call() throws Exception {
						return computable.compute(arg);
					}
				};
				FutureTask<V> ft = new FutureTask<V>(eval);
				f = cached.putIfAbsent(arg, ft);
				if (f == null) { // 说明没有老的计算值，这样判断就不会有重复的计算
					f = ft;
					ft.run();
				}
			}
			try {
				return f.get();
			} catch (CancellationException e) {
				cached.remove(arg, f);
			} catch (ExecutionException e) {
				throw new RuntimeException(e);
			}
		}
	}

}
